package hk.xing.boot.service.impl;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import hk.xing.boot.entity.Permission;
import hk.xing.boot.entity.Role;
import hk.xing.boot.entity.SysUser;
import hk.xing.boot.mapper.PermissionMapper;
import hk.xing.boot.mapper.RoleMapper;
import hk.xing.boot.mapper.SysUserMapper;
import hk.xing.boot.service.SysUserService;
import hk.xing.boot.utils.AESUtils;
import hk.xing.boot.vo.SysUserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.HexFormat;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


@Service
@Slf4j
public class SysUserServiceImpl implements SysUserService {

    @Resource
    private SysUserMapper userMapper;

    @Resource
    private AESUtils aesUtils;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private PermissionMapper permissionMapper;



    @Override
    public SysUser validateLoginUser(String account , String password) throws Exception {

        //根据账户获取对应用户
        SysUser currentLoginUser = userMapper.findSysUserByAccount(account);

        //如果根据账户查不到用户，则抛出异常
        if (ObjectUtil.isEmpty(currentLoginUser)){
            throw new RuntimeException("当前账户不存在");
        }

        //对密码进行加盐并加密处理
        String encodePassword = loginUserPasswordHandle(password, currentLoginUser);

        //处理之后与数据库账户信息进行比较
        if (currentLoginUser.getPassword().equals(encodePassword)) {

            //如果密码匹配则登录成功，并构建Token
            StpUtil.login(currentLoginUser.getId(),
                    new SaLoginParameter()
                    .setExtra("account", currentLoginUser.getAccount())
                    .setExtra("email", currentLoginUser.getEmail())
                    .setExtra("id", currentLoginUser.getId())
                    .setExtra("phone" , currentLoginUser.getPhone())
                    );

            return currentLoginUser;
        }else{
            throw new RuntimeException("密码错误");
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doSignUp(SysUser sysUser) throws Exception {
        String dbPassword = loginUserPasswordHandle(sysUser.getPassword(), sysUser);
        //生成对应的加密密码重新进行赋值
        sysUser.setPassword(dbPassword);
        //TODO 用户信息进行双向加密
        userMapper.insertSysUser(sysUser);
    }


    @Override
    public SysUserVo getCurrentUser() {
        //获取当前登录用户Id
        Long currentLoginUserId = StpUtil.getLoginIdAsLong();
        //根据Id查询用户角色
        SysUserVo sysUserVo = roleMapper.selectRolesByUserId(currentLoginUserId);
        //拿到角色id
        List<Long> roleIds = sysUserVo.getRoles().stream().map(Role::getRoleId).collect(Collectors.toList());
        //根据角色ID获取对应的权限
        List<Permission> permissions = null;
        if (ObjectUtil.isNotEmpty(roleIds)){
            permissions = permissionMapper.selectByRoleIds(roleIds);
        }
        if (ObjectUtil.isNotEmpty(permissions)){
            //将权限信息进行格式化
            Set<String> permissionList = permissions.stream().map(Permission::getPermKey).collect(Collectors.toSet());
            sysUserVo.setPermissions(permissionList);
        }
        return sysUserVo;
    }

    @Override
    public void logout() {
        //获取当前登录用户ID
        long currentLoginUserId = StpUtil.getLoginIdAsLong();
        if (ObjectUtil.isNotEmpty(currentLoginUserId)){
            //执行用户下线
            StpUtil.logout(currentLoginUserId);
        }
    }


    @Override
    public Set<String> getCurrentUserPermission() {
        return getCurrentUser().getPermissions();
    }

    @Override
    public SysUserVo getCurrentUserRoles() {
        //获取当前登录用户Id
        Long currentLoginUserId = StpUtil.getLoginIdAsLong();
        //根据Id查询用户角色
        return roleMapper.selectRolesByUserId(currentLoginUserId);
    }


    private String loginUserPasswordHandle(String password, SysUser currentLoginUser) throws Exception {

        String salt = currentLoginUser.getSalt();

        //如果盐值为空，则生成对应盐值
        if (StrUtil.isBlank(salt)){
            salt = RandomUtil.randomString(6);
            //重新设置Salt
            currentLoginUser.setSalt(salt);
        }

        String saltAfterPassword = hmacSha256(salt, password);

        // sha256加密
        return SaSecureUtil.sha256(saltAfterPassword);
    }


    // HMAC-SHA256盐值处理
    private String hmacSha256(String salt, String data) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(salt.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(secretKey);
        byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return HexFormat.of().formatHex(hash);
    }
}




